﻿namespace Comet.Presentation
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using EnvDTE;
    using Comet.Infrastructure;

    /// <summary>   
    ///     Interface for views that help to generate a constructor
    ///     from a set data members. 
    /// </summary>
    /// <remarks>   
    ///     Simon, 10.07.2010. 
    /// </remarks>
    public interface IDataMembersView
    {
        #region Delegates and Events (1) 

        // Events (1) 

        /// <summary> Event queue for all listeners interested in ApplyChanges events. </summary>
        event EventHandler ChangesAccepted;

        #endregion Delegates and Events 

        #region Operations (2) 

        /// <summary>   
        ///     Adds the data member described by dataMemberPresenter to
        ///     the view. 
        /// </summary>
        /// <param name="dataMemberPresenter">  The data member presenter. </param>
        void AddDataMember(DataMemberPresenter dataMemberPresenter);

        /// <summary>   
        ///     Removes the data member described by dataMemberPresenter
        ///     from the view.
        /// </summary>
        /// <param name="dataMemberPresenter">  The data member presenter. </param>
        void RemoveDataMember(DataMemberPresenter dataMemberPresenter);

        #endregion Operations 
    }

    /// <summary>   
    ///     Presenter for views thap help to generate a constructor
    ///     from a give set of data members.
    /// </summary>
    /// <remarks>   
    ///     Simon, 10.07.2010. 
    /// </remarks>
    public class DataMembersPresenter
    {
        #region Fields

        private IDataMembersView view;
        CodeClass codeClass;

        #endregion

        #region Backing Fields

        BindingList<DataMemberPresenter> dataMemberPresenters = new BindingList<DataMemberPresenter>();

        #endregion

        #region Public Properties

        IList<DataMemberPresenter> DataMemberPresenters
        {
            get
            {
                return dataMemberPresenters;
            }
        }

        public IEnumerable<DataMemberPresenter> SelectedDataMembers
        {
            get;
            private set;
        }

        public IDataMembersView View
        {
            get { return (view); }
            set
            {
                if (this.view == value)
                {
                    return;
                }

                if (view != null)
                {
                    view.ChangesAccepted -= this.View_ChangesAccepted;
                }

                view = value;

                if (view != null)
                {
                    view.ChangesAccepted += this.View_ChangesAccepted;
                }
                
                UpdateView();
            }
        }

        
        #endregion

        #region Constructors

        public DataMembersPresenter(CodeClass codeClass)
        {
            if (codeClass == null)
            {
                throw new ArgumentNullException("codeClass");
            }

            this.codeClass = codeClass;
            this.dataMemberPresenters.ListChanged += this.DataMemberPresenters_ListChanged;
            SelectedDataMembers = Enumerable.Empty<DataMemberPresenter>();

            ExtractDataMembers(codeClass);
        }

        public DataMembersPresenter(CodeClass codeClass, IDataMembersView view) : this(codeClass)
        {
            if (view == null)
            {
                throw new ArgumentNullException("view");
            }

            this.View = view;
            this.View.ChangesAccepted += new EventHandler(View_ChangesAccepted);
        }

        #endregion

        #region Private Methods

        private void DataMemberPresenters_ListChanged(object sender, ListChangedEventArgs e)
        {
            if (this.View != null)
            {
                if (e.ListChangedType == ListChangedType.ItemAdded)
                {
                    this.View.AddDataMember(this.DataMemberPresenters[e.NewIndex]);
                }
                else if (e.ListChangedType == ListChangedType.ItemDeleted)
                {
                    this.View.RemoveDataMember(this.DataMemberPresenters[e.NewIndex]);
                }
            }
        }

        private void View_ChangesAccepted(object source, EventArgs e)
        {
            SelectedDataMembers = dataMemberPresenters.Where(x => x.IsSelected)
                                                      .OrderBy(x => x.DataMemberType);
        }

        private void UpdateView()
        {
            if (this.View != null)
            {
                foreach (DataMemberPresenter dataMemberPresenter in this.DataMemberPresenters)
                {
                    this.View.AddDataMember(dataMemberPresenter);
                }
            }
        }

        private void ExtractDataMembers(CodeClass codeClass)
        {
            ExtractedDataMembers extractedDataMembers = CometUtils.ExtractSettableNonStaticDataMembers(codeClass);

            //non-static fields
            var fields = extractedDataMembers.Fields;

            //non-static settable properties
            var properties = extractedDataMembers.Properties;

            foreach (var field in fields)
            {
                DataMemberPresenters.Add(new DataMemberPresenter(field));
            }

            foreach (var property in properties)
            {
                DataMemberPresenters.Add(new DataMemberPresenter(property));
            }
        }

        #endregion
    }
}
